//package fr.loof.fonzie.gigai;
//
//import static junit.framework.Assert.fail;
//
//import java.lang.reflect.Field;
//import java.util.ArrayList;
//import java.util.Collections;
//import java.util.Comparator;
//import java.util.HashMap;
//import java.util.HashSet;
//import java.util.Iterator;
//import java.util.List;
//import java.util.Map;
//import java.util.Set;
//
//import org.eclipse.persistence.expressions.ExpressionOperator;
//import org.eclipse.persistence.internal.jpa.parsing.AndNode;
//import org.eclipse.persistence.internal.jpa.parsing.AttributeNode;
//import org.eclipse.persistence.internal.jpa.parsing.DotNode;
//import org.eclipse.persistence.internal.jpa.parsing.EqualsNode;
//import org.eclipse.persistence.internal.jpa.parsing.FromNode;
//import org.eclipse.persistence.internal.jpa.parsing.GreaterThanEqualToNode;
//import org.eclipse.persistence.internal.jpa.parsing.GreaterThanNode;
//import org.eclipse.persistence.internal.jpa.parsing.IdentificationVariableDeclNode;
//import org.eclipse.persistence.internal.jpa.parsing.JPQLParseTree;
//import org.eclipse.persistence.internal.jpa.parsing.JoinDeclNode;
//import org.eclipse.persistence.internal.jpa.parsing.LessThanEqualToNode;
//import org.eclipse.persistence.internal.jpa.parsing.LessThanNode;
//import org.eclipse.persistence.internal.jpa.parsing.LiteralNode;
//import org.eclipse.persistence.internal.jpa.parsing.Node;
//import org.eclipse.persistence.internal.jpa.parsing.NotEqualsNode;
//import org.eclipse.persistence.internal.jpa.parsing.NotNode;
//import org.eclipse.persistence.internal.jpa.parsing.OrNode;
//import org.eclipse.persistence.internal.jpa.parsing.OrderByItemNode;
//import org.eclipse.persistence.internal.jpa.parsing.OrderByNode;
//import org.eclipse.persistence.internal.jpa.parsing.ParameterNode;
//import org.eclipse.persistence.internal.jpa.parsing.RangeDeclNode;
//import org.eclipse.persistence.internal.jpa.parsing.SortDirectionNode;
//import org.eclipse.persistence.internal.jpa.parsing.VariableNode;
//import org.eclipse.persistence.internal.jpa.parsing.WhereNode;
//import org.eclipse.persistence.internal.jpa.parsing.jpql.JPQLParserFactory;
//import org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParser;
//
///**
// * @author <a href="nicolas@apache.org">Nicolas De Loof</a>
// */
//public class InMemoryJPQLQuery
//{
//    private JPQLParseTree root;
//
//    private Map<String, Object> params = new HashMap<String, Object>();
//
//    private Map<String, Object> variables = new HashMap<String, Object>();
//
//    public InMemoryJPQLQuery( String jpql )
//    {
//        super();
//        JPQLParser parser = (JPQLParser) new JPQLParserFactory().parseEJBQLString( jpql );
//        root = (JPQLParseTree) parser.getRootNode();
//    }
//
//    public void setParameter( String name, Object value )
//    {
//        params.put( name, value );
//    }
//
//    public List execute( Set database )
//    {
//        // Apply FROM clause
//        Set candidates = getCandidatesUsingFromClause( database );
//
//        // Apply WHERE clause
//        applyWhereClause( candidates );
//
//        // Apply ORDER BY clause
//        List result = applyOrderByClause( candidates );
//
//        return result;
//    }
//
//    private Set getCandidatesUsingFromClause( Set database )
//    {
//        FromNode from = root.getFromNode();
//        List<IdentificationVariableDeclNode> declarations = from.getDeclarations();
//        RangeDeclNode declNode = (RangeDeclNode) declarations.get( 0 );
//        String alias = declNode.getVariableName();
//        String entity = declNode.getAbstractSchemaName();
//
//        Set candidates = new HashSet();
//        for ( Object e : database )
//        {
//            if ( e.getClass().getSimpleName().equals( entity ) )
//            {
//                candidates.add( e );
//            }
//        }
//        return candidates;
//    }
//
//    private void applyWhereClause( Set candidates )
//    {
//        WhereNode where = root.getWhereNode();
//        if ( where != null )
//        {
//            FromNode from = root.getFromNode();
//            for ( Iterator iterator = candidates.iterator(); iterator.hasNext(); )
//            {
//                Object candidate = iterator.next();
//
//                List<IdentificationVariableDeclNode> declarations = from.getDeclarations();
//                for ( IdentificationVariableDeclNode decl : declarations )
//                {
//                    if ( decl instanceof RangeDeclNode )
//                    {
//                        RangeDeclNode range = (RangeDeclNode) decl;
//                        String alias = range.getVariableName();
//                        variables.put( range.getVariableName(), candidate );
//                    }
//                    if ( decl instanceof JoinDeclNode )
//                    {
//                        JoinDeclNode join = (JoinDeclNode) decl;
//                        variables.put( join.getVariableName(), eval( join.getPath(), candidate ) );
//                    }
//                }
//
//                if ( !(Boolean) eval( where.getLeft(), candidate ) )
//                {
//                    iterator.remove();
//                }
//            }
//        }
//    }
//
//    private List applyOrderByClause( Set candidates )
//    {
//        List result = new ArrayList( candidates );
//
//        OrderByNode orderBy = root.getOrderByNode();
//        if ( orderBy == null )
//        {
//            return result;
//        }
//        final List<OrderByItemNode> ordering = orderBy.getOrderByItems();
//
//        Comparator comparator = new Comparator()
//        {
//            public int compare( Object o1, Object o2 )
//            {
//                int compare = 0;
//                for ( OrderByItemNode orderByItemNode : ordering )
//                {
//                    Node node = orderByItemNode.getOrderByItem();
//                    Comparable c1 = (Comparable) eval( node, o1 );
//                    Comparable c2 = (Comparable) eval( node, o2 );
//                    compare = c1.compareTo( c2 );
//
//                    SortDirectionNode dir = orderByItemNode.getDirection();
//                    if ( dir != null )
//                    {
//                        if ( dir.getSortDirection() == ExpressionOperator.Descending )
//                        {
//                            compare = -1 * compare;
//                        }
//                    }
//                    if ( compare != 0 )
//                    {
//                        break;
//                    }
//                }
//                return compare;
//            }
//        };
//
//        Collections.sort( result, comparator );
//        return result;
//    }
//
//    /**
//     * @param node
//     * @param object TODO
//     */
//    private Object eval( Node node, Object o )
//    {
//        if ( node instanceof AndNode )
//        {
//            Boolean left = (Boolean) eval( node.getLeft(), o );
//            Boolean right = (Boolean) eval( node.getRight(), o );
//            return left && right;
//        }
//        if ( node instanceof OrNode )
//        {
//            Boolean left = (Boolean) eval( node.getLeft(), o );
//            Boolean right = (Boolean) eval( node.getRight(), o );
//            return left || right;
//        }
//        if ( node instanceof NotNode )
//        {
//            Boolean left = (Boolean) eval( node.getLeft(), o );
//            return !left;
//        }
//        if ( node instanceof EqualsNode )
//        {
//            Object left = eval( node.getLeft(), o );
//            Object right = eval( node.getRight(), o );
//            return ( left.equals( right ) );
//        }
//        if ( node instanceof NotEqualsNode )
//        {
//            Object left = eval( node.getLeft(), o );
//            Object right = eval( node.getRight(), o );
//            return ( !left.equals( right ) );
//        }
//        if ( node instanceof LessThanNode )
//        {
//            Comparable left = (Comparable) eval( node.getLeft(), o );
//            Comparable right = (Comparable) eval( node.getRight(), o );
//            return left.compareTo( right ) < 0;
//        }
//        if ( node instanceof LessThanEqualToNode )
//        {
//            Comparable left = (Comparable) eval( node.getLeft(), o );
//            Comparable right = (Comparable) eval( node.getRight(), o );
//            return left.compareTo( right ) <= 0;
//        }
//        if ( node instanceof GreaterThanNode )
//        {
//            Comparable left = (Comparable) eval( node.getLeft(), o );
//            Comparable right = (Comparable) eval( node.getRight(), o );
//            return left.compareTo( right ) > 0;
//        }
//        if ( node instanceof GreaterThanEqualToNode )
//        {
//            Comparable left = (Comparable) eval( node.getLeft(), o );
//            Comparable right = (Comparable) eval( node.getRight(), o );
//            return left.compareTo( right ) >= 0;
//        }
//        if ( node instanceof LiteralNode )
//        {
//            return ( (LiteralNode) node ).getLiteral();
//        }
//        if ( node instanceof DotNode )
//        {
//            Object source = eval( node.getLeft(), o );
//            return eval( node.getRight(), source );
//        }
//        if ( node instanceof VariableNode )
//        {
//            String name = ( (VariableNode) node ).getVariableName();
//            return variables.get( name );
//        }
//        if ( node instanceof ParameterNode )
//        {
//            String paramName = ( (ParameterNode) node ).getParameterName();
//            return params.get( paramName );
//        }
//        if ( node instanceof AttributeNode )
//        {
//            String name = ( (AttributeNode) node ).getAttributeName();
//            try
//            {
//                Field f = o.getClass().getDeclaredField( name );
//                f.setAccessible( true );
//                return f.get( o );
//            }
//            catch ( Exception e )
//            {
//                fail( "Failed to read attribute " + name + " on " + o );
//            }
//        }
//        throw new UnsupportedOperationException( "Unsupported node type " + node );
//    }
//
//}
